package com.danicsoft.daide.token;

import java.io.UnsupportedEncodingException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;

/**
 * <p>
 * The <code>TokenMap</code> class encapsulates the mapping between strings
 * and token and vise versa. It also has some facilities for verifying a token
 * is of a specific type
 * </p>
 * <p>
 * <em>Note</em>: Parts of this class are based on Henrik Bylund's
 * <code>dip.daide.comm.Token</code> class, copyright 2002, 2003 and 2004
 * Henrik Bylund. For more information, see Henrik's Framework.
 * </p>
 * 
 * @author Daniel Yule (daniel.yule@gmail.com)
 * @version 1.0
 */
public final class TokenMap {

	/**
	 * The eight compass point coast tokens.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Coasts extends TypeClass {
		/**
		 * East coast
		 */
		public final static byte ECS = 0x04;

		/**
		 * North coast
		 */
		public final static byte NCS = 0x00;

		/**
		 * Northeast coast
		 */
		public final static byte NEC = 0x02;

		/**
		 * Northwest coast
		 */
		public final static byte NWC = 0x0E;

		/**
		 * South coast
		 */
		public final static byte SCS = 0x08;

		/**
		 * Southeast coast
		 */
		public final static byte SEC = 0x06;

		/**
		 * Southwest coast
		 */
		public final static byte SWC = 0x0A;

		/**
		 * West coast
		 */
		public final static byte WCS = 0x0C;

		@Override
		public byte getType() {
			return COASTS;
		}

	}

	/**
	 * Commands sent from the server to the client or vise versa.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Commands extends TypeClass {

		/**
		 * Admin message
		 */
		public final static byte ADM = 0x1D;

		/**
		 * Power in civil disorder
		 */
		public final static byte CCD = 0x00;

		/**
		 * Draw
		 */
		public final static byte DRW = 0x01;

		/**
		 * Message From
		 */
		public final static byte FRM = 0x02;

		/**
		 * Go flag
		 */
		public final static byte GOF = 0x03;

		/**
		 * Hello
		 */
		public final static byte HLO = 0x04;

		/**
		 * History
		 */
		public final static byte HST = 0x05;

		/**
		 * Huh (syntax error)
		 */
		public final static byte HUH = 0x06;

		/**
		 * I am (reconnecting)
		 */
		public final static byte IAM = 0x07;

		/**
		 * Load game
		 */
		public final static byte LOD = 0x08;

		/**
		 * Map to be used
		 */
		public final static byte MAP = 0x09;

		/**
		 * Map definition
		 */
		public final static byte MDF = 0x0A;

		/**
		 * Missing orders
		 */
		public final static byte MIS = 0x0B;

		/**
		 * Name
		 */
		public final static byte NME = 0x0C;

		/**
		 * Not
		 */
		public final static byte NOT = 0x0D;

		/**
		 * Current army positions
		 */
		public final static byte NOW = 0x0E;

		/**
		 * Observer
		 */
		public final static byte OBS = 0x0F;

		/**
		 * Sign off.
		 */
		public final static byte OFF = 0x10;

		/**
		 * Order
		 */
		public final static byte ORD = 0x11;

		/**
		 * Power has been eliminated
		 */
		public final static byte OUT = 0x12;

		/**
		 * Parenthesis error
		 */
		public final static byte PRN = 0x13;

		/**
		 * Rejected!
		 */
		public final static byte REJ = 0x14;

		/**
		 * Supply centre ownership
		 */
		public final static byte SCO = 0x15;

		/**
		 * Solo victory
		 */
		public final static byte SLO = 0x16;

		/**
		 * Summary of game (Note this token used to be defined as WRT)
		 */
		public final static byte SMR = 0x1E;

		/**
		 * Send press
		 */
		public final static byte SND = 0x17;

		/**
		 * Submit order
		 */
		public final static byte SUB = 0x18;

		/**
		 * Save game
		 */
		public final static byte SVE = 0x19;

		/**
		 * Thanks (order note)
		 */
		public final static byte THX = 0x1A;

		/**
		 * Time left until end of phase
		 */
		public final static byte TME = 0x1B;

		/**
		 * Accepted
		 */
		public final static byte YES = 0x1C;

		@Override
		public byte getType() {
			return COMMANDS;
		}

	}

	/**
	 * Miscellaneous tokens, such as parenthesis.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Miscellaneous extends TypeClass {

		/**
		 * Opening parenthesis.
		 */
		public final static byte BRA = 0x00;

		/**
		 * Closing parenthesis.
		 */
		public final static byte KET = 0x01;

		@Override
		public byte getType() {
			return MISC;
		}

	}

	/**
	 * Notes for orders token types.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class OrderNotes extends TypeClass {

		/**
		 * Server is processing a turn (Removed)
		 * 
		 * @deprecated
		 */

		@Deprecated
		public final static byte BPR = 0x01;

		/**
		 * No coast specified for fleet build in a multi-coastal province, or an
		 * attempt to build a fleet inland or an army at sea
		 */
		public final static byte CST = 0x02;

		/**
		 * Not an empty supply centre
		 */
		public final static byte ESC = 0x03;

		/**
		 * Not adjacent
		 */
		public final static byte FAR = 0x04;

		/**
		 * Not a home supply centre
		 */
		public final static byte HSC = 0x05;

		/**
		 * Might be valid
		 */
		public final static byte MBV = 0x00;

		/**
		 * Not at sea (for a convoying fleet).
		 */
		public final static byte NAS = 0x06;

		/**
		 * No more builds allowed
		 */
		public final static byte NMB = 0x07;

		/**
		 * No more removals allowed
		 */
		public final static byte NMR = 0x08;

		/**
		 * No retreat needed for that unit.
		 */
		public final static byte NRN = 0x09;

		/**
		 * Not the right season
		 */
		public final static byte NRS = 0x0A;

		/**
		 * No such army (for the unit being ordered to CTO or for the unit being
		 * CVYed)
		 */
		public final static byte NSA = 0x0B;

		/**
		 * Not a supply centre.
		 */
		public final static byte NSC = 0x0C;

		/**
		 * No such fleet (in the VIA section of CTO or the unit performing a
		 * CVY)
		 */
		public final static byte NSF = 0x0D;

		/**
		 * No such province
		 */
		public final static byte NSP = 0x0E;

		/**
		 * No such type
		 * 
		 * @deprecated
		 */
		@Deprecated
		public final static byte NST = 0x0F;

		/**
		 * No such unit
		 */
		public final static byte NSU = 0x10;

		/**
		 * Not a valid retreat space
		 */
		public final static byte NVR = 0x11;

		/**
		 * Not your unit
		 */
		public final static byte NYU = 0x12;

		/**
		 * Not your supply centre
		 */
		public final static byte YSC = 0x13;

		@Override
		public byte getType() {
			return ORDER_NOTES;
		}

	}

	/**
	 * Orders token types for units.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Orders extends TypeClass {

		/**
		 * Build unit
		 */
		public final static byte BLD = -0x80;

		/**
		 * Move by convoy to
		 */
		public final static byte CTO = 0x20;

		/**
		 * Convoy
		 */
		public final static byte CVY = 0x21;

		/**
		 * Disband
		 */
		public final static byte DSB = 0x40;

		/**
		 * Hold
		 */
		public final static byte HLD = 0x22;

		/**
		 * Move to
		 */
		public final static byte MTO = 0x23;

		/**
		 * Remove unit
		 */
		public final static byte REM = -0x7F;

		/**
		 * Retreat to
		 */
		public final static byte RTO = 0x41;

		/**
		 * Support
		 */
		public final static byte SUP = 0x24;

		/**
		 * Move via
		 */
		public final static byte VIA = 0x25;

		/**
		 * Waive build
		 */
		public final static byte WVE = -0x7E;

		@Override
		public byte getType() {
			return ORDERS;
		}

	}

	/**
	 * Parameters for command tokens.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Parameters extends TypeClass {

		/**
		 * Any orders accepted
		 */
		public final static byte AOA = 0x00;

		/**
		 * Build time limit
		 */
		public final static byte BTL = 0x01;

		/**
		 * Deadline stops on disconnection
		 */
		public final static byte DSD = 0x0D;

		/**
		 * Error after this token
		 */
		public final static byte ERR = 0x02;

		/**
		 * Syntax level
		 */
		public final static byte LVL = 0x03;

		/**
		 * Must retreat to
		 */
		public final static byte MRT = 0x04;

		/**
		 * Move time limit
		 */
		public final static byte MTL = 0x05;

		/**
		 * No press during build phases
		 */
		public final static byte NPB = 0x06;

		/**
		 * No press suring retreat phases
		 */
		public final static byte NPR = 0x07;

		/**
		 * Partial draws are allowed
		 */
		public final static byte PDA = 0x08;

		/**
		 * Number of seconds before a movement deadline that all press between
		 * powers must stop
		 */
		public final static byte PTL = 0x09;

		/**
		 * Retreat time limit
		 */
		public final static byte RTL = 0x0A;

		/**
		 * Unowned (supply centre)
		 */
		public final static byte UNO = 0x0B;

		@Override
		public byte getType() {
			return PARAMETERS;
		}

	}

	/**
	 * Tokens for the different phases (Spring, Summer, etc).
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Phases extends TypeClass {
		/**
		 * Autumn (Retreat)
		 */
		public final static byte AUT = 0x03;

		/**
		 * Fall (Movement)
		 */
		public final static byte FAL = 0x02;

		/**
		 * Spring (Movement)
		 */
		public final static byte SPR = 0x00;

		/**
		 * Summer (Retreat)
		 */
		public final static byte SUM = 0x01;

		/**
		 * Winter (Build)
		 */
		public final static byte WIN = 0x04;

		@Override
		public byte getType() {
			return PHASES;
		}

	}

	/**
	 * Power token types.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Powers extends TypeClass {

		/**
		 * Austria
		 */
		public final static byte AUS = 0x00;

		/**
		 * England
		 */
		public final static byte ENG = 0x01;

		/**
		 * France
		 */
		public final static byte FRA = 0x02;

		/**
		 * Germany
		 */
		public final static byte GER = 0x03;

		/**
		 * Italy
		 */
		public final static byte ITA = 0x04;

		/**
		 * Russia
		 */
		public final static byte RUS = 0x05;

		/**
		 * Turkey
		 */
		public final static byte TUR = 0x06;

		@Override
		public byte getType() {
			return POWERS;
		}

		@Override
		public boolean isOfType(Token token) {
			return (token.getType() == PARAMETERS && token.getData().equals(Parameters.UNO)) || super.isOfType(token);
		}

	}

	/**
	 * Press tokens for information sent between players.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Press extends TypeClass {

		/**
		 * Propose an alliance
		 */
		public final static byte ALY = 0x00;

		/**
		 * Conditional and
		 */
		public final static byte AND = 0x01;

		/**
		 * Blind carbon copy
		 */
		public final static byte BCC = 0x23;

		/**
		 * None of your business
		 */
		public final static byte BWX = 0x02;

		/**
		 * Choose
		 */
		public final static byte CHO = 0x22;

		/**
		 * De-militarized zone
		 */
		public final static byte DMZ = 0x03;

		/**
		 * Conditional else
		 */
		public final static byte ELS = 0x04;

		/**
		 * Explain an action
		 */
		public final static byte EXP = 0x05;

		/**
		 * This statement is fact
		 */
		public final static byte FCT = 0x07;

		/**
		 * For the specified turn
		 */
		public final static byte FOR = 0x08;

		/**
		 * Forward this message
		 */
		public final static byte FWD = 0x06;

		/**
		 * How to attack
		 */
		public final static byte HOW = 0x09;

		/**
		 * I don't know
		 */
		public final static byte IDK = 0x0A;

		/**
		 * If
		 */
		public final static byte IFF = 0x0B;

		/**
		 * Insist
		 */
		public final static byte INS = 0x0C;

		/**
		 * I owe you
		 */
		public final static byte IOU = 0x0D;

		/**
		 * Occupy
		 */
		public final static byte OCC = 0x0E;

		/**
		 * Conditional OR
		 */
		public final static byte ORR = 0x0F;

		/**
		 * Peace
		 */
		public final static byte PCE = 0x10;

		/**
		 * Position on board
		 */
		public final static byte POB = 0x11;

		/**
		 * Puppet
		 * 
		 * @deprecated
		 */
		@Deprecated
		public final static byte PPT = 0x12;

		/**
		 * Propose
		 */
		public final static byte PRP = 0x13;

		/**
		 * Query
		 */
		public final static byte QRY = 0x14;

		/**
		 * Supply centre distribution
		 */
		public final static byte SCD = 0x15;

		/**
		 * I'm sorry
		 */
		public final static byte SRY = 0x16;

		/**
		 * Suggest
		 */
		public final static byte SUG = 0x17;

		/**
		 * I think
		 */
		public final static byte THK = 0x18;

		/**
		 * Then
		 */
		public final static byte THN = 0x19;

		/**
		 * Try the following tokens (for compatibility)
		 */
		public final static byte TRY = 0x1A;

		/**
		 * Unit
		 */
		public final static byte UNT = 0x24;

		/**
		 * You owe me (Removed)
		 * 
		 * @deprecated
		 */
		@Deprecated
		public final static byte UOM = 0x1B;

		/**
		 * Versus
		 */
		public final static byte VSS = 0x1C;

		/**
		 * What to do with
		 */
		public final static byte WHT = 0x1D;

		/**
		 * Why
		 */
		public final static byte WHY = 0x1E;

		/**
		 * Moves to do
		 */
		public final static byte XDO = 0x1F;

		/**
		 * X owes Y
		 */
		public final static byte XOY = 0x20;

		/**
		 * You provide the order for these units
		 */
		public final static byte YDO = 0x21;

		@Override
		public byte getType() {
			return PRESS;
		}

	}

	/**
	 * Province token types.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class Provinces extends TypeClass {

		/**
		 * Adriaric Sea
		 */
		public final static byte ADR = 0x0E;

		/**
		 * Aegean Sea
		 */
		public final static byte AEG = 0x0F;

		/**
		 * Albania
		 */
		public final static byte ALB = 0x21;

		/**
		 * Ankara
		 */
		public final static byte ANK = 0x30;

		/**
		 * Apulia
		 */
		public final static byte APU = 0x22;

		/**
		 * Armenia
		 */
		public final static byte ARM = 0x23;

		/**
		 * Baltic Sea
		 */
		public final static byte BAL = 0x10;

		/**
		 * Barents Sea
		 */
		public final static byte BAR = 0x11;

		/**
		 * Belgum
		 */
		public final static byte BEL = 0x31;

		/**
		 * Berlin
		 */
		public final static byte BER = 0x32;

		/**
		 * Black Sea
		 */
		public final static byte BLA = 0x12;

		/**
		 * Bohemia
		 */
		public final static byte BOH = 0x00;

		/**
		 * Brest
		 */
		public final static byte BRE = 0x33;

		/**
		 * Budapest
		 */
		public final static byte BUD = 0x07;

		/**
		 * Bulgaria
		 */
		public final static byte BUL = 0x48;

		/**
		 * Burgandy
		 */
		public final static byte BUR = 0x01;

		/**
		 * Clyde
		 */
		public final static byte CLY = 0x24;

		/**
		 * Constantinople
		 */
		public final static byte CON = 0x34;

		/**
		 * Denmark
		 */
		public final static byte DEN = 0x35;

		/**
		 * Eastern Mediterranean Sea
		 */
		public final static byte EAS = 0x13;

		/**
		 * English Chanel
		 */
		public final static byte ECH = 0x14;

		/**
		 * Edinburgh
		 */
		public final static byte EDI = 0x36;

		/**
		 * Finland
		 */
		public final static byte FIN = 0x25;

		/**
		 * Galecia
		 */
		public final static byte GAL = 0x02;

		/**
		 * Gascony
		 */
		public final static byte GAS = 0x26;

		/**
		 * Gulf of Bothnia
		 */
		public final static byte GOB = 0x15;

		/**
		 * Gulf of Lyons
		 */
		public final static byte GOL = 0x16;

		/**
		 * Greece
		 */
		public final static byte GRE = 0x37;

		/**
		 * Helgoland Bight
		 */
		public final static byte HEL = 0x17;

		/**
		 * Holland
		 */
		public final static byte HOL = 0x38;

		/**
		 * Ionian Sea
		 */
		public final static byte ION = 0x18;

		/**
		 * Irish Sea
		 */
		public final static byte IRI = 0x19;

		/**
		 * Kiev
		 */
		public final static byte KIE = 0x39;

		/**
		 * London
		 */
		public final static byte LON = 0x3A;

		/**
		 * Livonia
		 */
		public final static byte LVN = 0x27;

		/**
		 * Liverpool
		 */
		public final static byte LVP = 0x3B;

		/**
		 * Mid-Atlantic Ocean
		 */
		public final static byte MAO = 0x1A;

		/**
		 * Marseilles
		 */
		public final static byte MAR = 0x3C;

		/**
		 * Moscow
		 */
		public final static byte MOS = 0x08;

		/**
		 * Munich
		 */
		public final static byte MUN = 0x09;

		/**
		 * North Africa
		 */
		public final static byte NAF = 0x28;

		/**
		 * North Atlantic Ocean
		 */
		public final static byte NAO = 0x1B;

		/**
		 * Naples
		 */
		public final static byte NAP = 0x3D;

		/**
		 * North Sea
		 */
		public final static byte NTH = 0x1C;

		/**
		 * Norwegian sea
		 */
		public final static byte NWG = 0x1D;

		/**
		 * Norway
		 */
		public final static byte NWY = 0x3E;

		/**
		 * Paris
		 */
		public final static byte PAR = 0x0A;

		/**
		 * Picardy
		 */
		public final static byte PIC = 0x29;

		/**
		 * Piedmont
		 */
		public final static byte PIE = 0x2A;

		/**
		 * Portugal
		 */
		public final static byte POR = 0x3F;

		/**
		 * Prussia
		 */
		public final static byte PRU = 0x2B;

		/**
		 * Rome
		 */
		public final static byte ROM = 0x40;

		/**
		 * Ruhr
		 */
		public final static byte RUH = 0x03;

		/**
		 * Rumania
		 */
		public final static byte RUM = 0x41;

		/**
		 * Serbia
		 */
		public final static byte SER = 0x0B;

		/**
		 * Sevastopol
		 */
		public final static byte SEV = 0x42;

		/**
		 * Silesia
		 */
		public final static byte SIL = 0x04;

		/**
		 * Skagerrak
		 */
		public final static byte SKA = 0x1E;

		/**
		 * Smyrna
		 */
		public final static byte SMY = 0x43;

		/**
		 * Spain
		 */
		public final static byte SPA = 0x49;

		/**
		 * St. Petersburg
		 */
		public final static byte STP = 0x4A;

		/**
		 * Sweden
		 */
		public final static byte SWE = 0x44;

		/**
		 * Syria
		 */
		public final static byte SYR = 0x2C;

		/**
		 * Trieste
		 */
		public final static byte TRI = 0x45;

		/**
		 * Tunis
		 */
		public final static byte TUN = 0x46;

		/**
		 * Tuscany
		 */
		public final static byte TUS = 0x2D;

		/**
		 * Tyrolia
		 */
		public final static byte TYR = 0x05;

		/**
		 * Tyrrhenian Sea
		 */
		public final static byte TYS = 0x1F;

		/**
		 * Ukraine
		 */
		public final static byte UKR = 0x06;

		/**
		 * Venice
		 */
		public final static byte VEN = 0x47;

		/**
		 * Vienna
		 */
		public final static byte VIE = 0x0C;

		/**
		 * Wales
		 */
		public final static byte WAL = 0x2E;

		/**
		 * Warsaw
		 */
		public final static byte WAR = 0x0D;

		/**
		 * Western Mediterranean Sea
		 */
		public final static byte WES = 0x20;

		/**
		 * Yorkshire
		 */
		public final static byte YOR = 0x2F;

		@Override
		public byte getType() {
			return PROVINCES;
		}

		@Override
		protected byte getMask() {
			return PROVINCES_MASK;
		}

		@Override
		public boolean isOfType(Token token) {
			return token.isGroup() || super.isOfType(token);
		}

	}

	/**
	 * Results of orders token types.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 */
	public static class Results extends TypeClass {

		/**
		 * Move bounced
		 */
		public final static byte BNC = 0x01;

		/**
		 * Support was cut
		 */
		public final static byte CUT = 0x02;

		/**
		 * Convoy failed due to dislodged fleet
		 */
		public final static byte DSR = 0x03;

		/**
		 * Move failed (Removed)
		 * 
		 * @deprecated
		 */
		@Deprecated
		public final static byte FLD = 0x04;

		/**
		 * No such order
		 */
		public final static byte NSO = 0x05;

		/**
		 * Unit must retreat
		 */
		public final static byte RET = 0x06;

		/**
		 * Order succeeded
		 */
		public final static byte SUC = 0x00;

		@Override
		public byte getType() {
			return RESULTS;
		}

	}

	/**
	 * Works as an entry in the mapping array. It hashes the same as a
	 * StandardToken with the same data, so it can be retrieved using a
	 * <code>StandardToken</code>.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 * @version 1.0
	 */
	public static class TokenEntry implements CommonToken {
		/**
		 * The subtype of this token
		 */
		private byte subtype;

		/**
		 * The type of this token
		 */
		private byte type;

		/**
		 * Creates a new TokenEntry of the given type and subtype.
		 * 
		 * @param type
		 *        The type of this TokenEntry.
		 * @param subtype
		 *        The subtype of this TokenEntry.
		 */
		public TokenEntry(byte type, byte subtype) {
			this.type = type;
			this.subtype = subtype;
		}

		@Override
		public boolean equals(Object obj) {

			return obj == null ? false : hashCode() == obj.hashCode();
		}

		/**
		 * Gets the subtype.
		 * 
		 * @return the subtype
		 */
		public byte getSubType() {
			return subtype;
		}

		/**
		 * Thets the type.
		 * 
		 * @return the type
		 */
		public byte getType() {
			return type;
		}

		@Override
		public int hashCode() {
			return (short) (type << 8 | subtype);
		}
	}

	/**
	 * Unit token types.
	 * 
	 * @author Daniel Yule (daniel.yule@gmail.com)
	 */
	public static class UnitTypes extends TypeClass {

		/**
		 * Army
		 */
		public final static byte AMY = 0x00;

		/**
		 * Fleet
		 */
		public final static byte FLT = 0x01;

		@Override
		public byte getType() {
			return UNIT_TYPES;
		}

		@Override
		public boolean isOfType(Token token) {

			return token.isGroup() || super.isOfType(token);
		}

	}

	/**
	 * Provinces with two coasts and no supply centre.
	 */
	public final static byte BI_COASTAL_NON_SC = 0x56;

	/**
	 * Provinces with two coasta and a supply centre.
	 */
	public final static byte BI_COASTAL_SC = 0x57;

	/**
	 * Coastal provinces with no supply centres
	 */
	public final static byte COASTAL_NON_SC = 0x54;

	/**
	 * Coastal provinces with a supply centre.
	 */
	public final static byte COASTAL_SC = 0x55;

	/**
	 * The eight compass point coast tokens.
	 */
	public final static byte COASTS = 0x46;

	/**
	 * Commands sent from the server to the client or vise versa.
	 */
	public final static byte COMMANDS = 0x48;

	/**
	 * Internal representation of token group type.
	 */
	public final static byte GROUP = 0x59;

	/**
	 * Inland provinces with no supply centres.
	 */
	public final static byte INLAND_NON_SC = 0x50;

	/**
	 * Inland provinces with supply centres.
	 */
	public final static byte INLAND_SC = 0x51;

	/**
	 * Internal representation of integer token type.
	 */
	public final static byte INTEGER = 0x58;

	/**
	 * Miscellaneous tokens, such as parenthesis.
	 */
	public final static byte MISC = 0x40;

	/**
	 * Notes for orders token types.
	 */
	public final static byte ORDER_NOTES = 0x44;

	/**
	 * Orders token types for units.
	 */
	public final static byte ORDERS = 0x43;

	/**
	 * Parameters for command tokens.
	 */
	public final static byte PARAMETERS = 0x49;

	/**
	 * Tokens for the different phases (Spring, Summer, etc)
	 */
	public final static byte PHASES = 0x47;

	/**
	 * A powers object that can be used for checking type
	 */
	public static Powers powers = new Powers();

	/**
	 * Power token types.
	 */
	public final static byte POWERS = 0x41;

	/**
	 * Press tokens for information sent between players.
	 */
	public final static byte PRESS = 0x4A;

	/**
	 * An instance of the Provinces class, which can be used for type checking.
	 */
	public static Provinces provinces = new Provinces();

	/**
	 * The type for provinces, once the mask is applied. Province's type must by
	 * 01010xxx where x is don't care.
	 */
	public final static byte PROVINCES = 0x50;

	/**
	 * The mask for provinces. Province's type must by 01010xxx where x is don't
	 * care.
	 */
	public final static byte PROVINCES_MASK = (byte) 0xF8;

	/**
	 * Results of orders token types.
	 */
	public final static byte RESULTS = 0x45;

	/**
	 * Sea provinces with no supply centres.
	 */
	public final static byte SEA_NON_SC = 0x52;

	/**
	 * Sea provinces with supply centres.
	 */
	public final static byte SEA_SC = 0x53;

	/**
	 * A type for text tokens
	 */
	public final static byte TEXT = 0x4B;

	/**
	 * Unit token types.
	 */
	public final static byte UNIT_TYPES = 0x42;

	/**
	 * An invalid token;
	 */
	public static final byte INVALID = 0x02;

	/**
	 * The default mapping for tokens.
	 */
	private static TokenMap defaultMapping = new TokenMap();

	/**
	 * A parameters object that can be used for checking type.
	 */
	public static Parameters parameters = new Parameters();

	/**
	 * A UnitType Object that can be used for checking type.
	 */
	public static UnitTypes unit_types = new UnitTypes();

	/**
	 * A Results object that can be used for checking type.
	 */
	public static Results results = new Results();

	/**
	 * An Orders Object that can be used for checking type.
	 */
	public static Orders orders = new Orders();

	/**
	 * An OrderNotes object that can be used for checking type.
	 */
	public static OrderNotes order_notes = new OrderNotes();

	/**
	 * A Phases object that can be used for checking type.
	 */
	public static Phases phase = new Phases();

	/**
	 * Get a type class that will validate any group and the type given.
	 * 
	 * @param otherType
	 *        The type of token that is valid.
	 * @return A TypeClass.
	 */
	public static TypeClass groupAndOther(final TypeClass otherType) {
		return new TypeClass() {

			@Override
			public byte getType() {
				return 0;
			}

			@Override
			public boolean isOfType(Token token) {
				return token.isGroup() || otherType.isOfType(token);
			}

		};
	}

	/**
	 * Gets a command token of the specified type
	 * 
	 * @param commandType
	 *        The type of the command we wish to find. (eg HLO)
	 * @return A <code>StandardToken</code> containing a command of the
	 *         specified type.
	 */
	public static StandardToken getCommandToken(byte commandType) {
		return new StandardToken(COMMANDS, commandType, defaultMapping);
	}

	/**
	 * Gets a Order Note token of the specified type
	 * 
	 * @param note
	 *        The type of the Order Note we wish to find. (eg MBV)
	 * @return A <code>StandardToken</code> containing a Note of the specified
	 *         type.
	 */
	public static StandardToken getNoteToken(int note) {
		return new StandardToken(ORDER_NOTES, (byte) note, defaultMapping);
	}

	/**
	 * Gets a order token of the specified type
	 * 
	 * @param orderType
	 *        The type of the order we wish to find. (eg MTO)
	 * @return A <code>StandardToken</code> containing a order of the
	 *         specified type.
	 */
	public static StandardToken getOrderToken(byte orderType) {
		return new StandardToken(ORDERS, orderType, defaultMapping);
	}

	/**
	 * Gets a parameter token of the specified type
	 * 
	 * @param parameterType
	 *        The type of the parameter we wish to find. (eg AOA)
	 * @return A <code>StandardToken</code> containing a parameter of the
	 *         specified type.
	 */
	public static StandardToken getParameterToken(byte parameterType) {
		return new StandardToken(PARAMETERS, parameterType, defaultMapping);
	}

	/**
	 * Gets either an opening or closing parenthesis token
	 * 
	 * @param opening
	 *        True if you want an opening parenthesis, false otherwise.
	 * @return A <code>StandardToken</code> containing either an opening or a
	 *         closing parenthesis
	 */
	public static StandardToken getParenthesisToken(boolean opening) {
		if (opening) {
			return new StandardToken(MISC, Miscellaneous.BRA, defaultMapping);
		}

		return new StandardToken(MISC, Miscellaneous.KET, defaultMapping);
	}

	/**
	 * Creates a new phase token.
	 * 
	 * @param spr
	 *        The phase to create
	 * @return A token representing the given phase.
	 */
	public static StandardToken getPhaseToken(byte spr) {
		return new StandardToken(PHASES, spr, defaultMapping);
	}
	

	/**
	 * Gets a Order result token for the given note.
	 * 
	 * @param result
	 *        The result to retrieve a token for.
	 * @return A StandardToken that represents the given note.
	 */
	public static StandardToken getResultToken(byte result) {
		return new StandardToken(RESULTS, result, defaultMapping);
	}

	/**
	 * Gets a unit type of the specified type.
	 * 
	 * @param type
	 *        The type of unit (one of FLT or AMY).
	 * @return A StandardTokenn representing the unit type.
	 */
	public static StandardToken getUnitType(byte type) {
		return new StandardToken(UNIT_TYPES, type, defaultMapping);
	}

	/**
	 * Create a new Group that contains the information for a coastal unit type
	 * 
	 * @param coast
	 *        The coast to create the group for.
	 * @return A TokenGroup that represents a coast.
	 */
	public static TokenGroup getCoastalToken(byte coast) {
		TokenGroup rGroup = new TokenGroup();
		rGroup.add(getUnitType(UnitTypes.FLT));
		rGroup.add(new StandardToken(COASTS, coast, defaultMapping));
		return rGroup;
	}

	{
		bitsMap = new HashMap<CommonToken, String>();
		tokenMap = new HashMap<String, CommonToken>();
		rmTokens = new HashSet<CommonToken>();
		createTokenMap();
	}

	/** A <code>Token</code>-><code>String</code> mapping */
	private Map<CommonToken, String> bitsMap;

	/**
	 * Whether or not we are using the standard mapping
	 */
	private boolean isStandard = false;

	/**
	 * The set of tokens that make up the RM message.
	 */
	private Set<CommonToken> rmTokens;

	/** A <code>String</code>-><code>Token</code> mapping */
	private Map<String, CommonToken> tokenMap;

	/**
	 * Creates a new instance of <code>TokenMap</code> and adds the standard
	 * province and power tokens to it.
	 */
	public TokenMap() {
		addStandardTokens();

	}

	/**
	 * Creates a new TokenMap from the given Representation Message
	 * 
	 * @param message
	 *        The representation message to load from.
	 */
	public TokenMap(byte[] message) {
		if (message.length == 0) {
			addStandardTokens();
		}
		else {
			for (int i = 0; i < message.length; i += 6) {
				CommonToken bits = new TokenEntry(message[i], message[i + 1]);
				byte[] token = new byte[] { message[i + 2], message[i + 3], message[i + 4] };
				add(bits, new String(token));

			}
		}
	}

	/**
	 * Creates a new instance of <code>TokenMap</code> and adds the contents
	 * of the given mapping to it.
	 * 
	 * @param rmMap
	 *        A Mapping from tokens to strings that will be the representation
	 *        message.
	 */
	public TokenMap(Map<CommonToken, String> rmMap) {
		if (rmMap.size() == 0) {
			addStandardTokens();
		}
		else {
			addAll(rmMap);
		}
	}

	/**
	 * Adds a token to the mnemonic -> token and token -> mnemonic maps.
	 * 
	 * @param token
	 *        The token representation
	 * @param mnemonic
	 *        The mnemonic representation
	 */
	public void add(CommonToken token, String mnemonic) {
		add(mnemonic, token);

	}

	/**
	 * Adds a token to the mnemonic -> token and token -> mnemonic maps.
	 * 
	 * @param mnemonic
	 *        The mnemonic representation
	 * @param token
	 *        The token representation
	 */
	public void add(String mnemonic, CommonToken token) {
		add_private(mnemonic, token);
		rmTokens.add(token);
		isStandard = false;
	}

	/**
	 * Adds all the tokens specified to this token mapping.
	 * 
	 * @param tokenMapping
	 *        A Map from Tokens to Strings that this <code>TokenMap</code>
	 *        will add to its internal mapping.
	 */
	public void addAll(Map<CommonToken, String> tokenMapping) {
		for (CommonToken token : tokenMapping.keySet()) {
			add(token, tokenMapping.get(token));
		}
	}

	/**
	 * Adds the provincial and power tokens that come with any standard game, in
	 * lieu of the ones that are sent via the RM message.
	 */
	public void addStandardTokens() {
		// Powers (0x41)
		add("AUS", new TokenEntry(POWERS, Powers.AUS));
		add("ENG", new TokenEntry(POWERS, Powers.ENG));
		add("FRA", new TokenEntry(POWERS, Powers.FRA));
		add("GER", new TokenEntry(POWERS, Powers.GER));
		add("ITA", new TokenEntry(POWERS, Powers.ITA));
		add("RUS", new TokenEntry(POWERS, Powers.RUS));
		add("TUR", new TokenEntry(POWERS, Powers.TUR));
		// Inland non-SC provinces (0x50)
		add("BOH", new TokenEntry(INLAND_NON_SC, (byte) 0x00));
		add("BUR", new TokenEntry(INLAND_NON_SC, (byte) 0x01));
		add("GAL", new TokenEntry(INLAND_NON_SC, (byte) 0x02));
		add("RUH", new TokenEntry(INLAND_NON_SC, (byte) 0x03));
		add("SIL", new TokenEntry(INLAND_NON_SC, (byte) 0x04));
		add("TYR", new TokenEntry(INLAND_NON_SC, (byte) 0x05));
		add("UKR", new TokenEntry(INLAND_NON_SC, (byte) 0x06));
		// Inland SC provinces (0x51)
		add("BUD", new TokenEntry(INLAND_SC, (byte) 0x07));
		add("MOS", new TokenEntry(INLAND_SC, (byte) 0x08));
		add("MUN", new TokenEntry(INLAND_SC, (byte) 0x09));
		add("PAR", new TokenEntry(INLAND_SC, (byte) 0x0A));
		add("SER", new TokenEntry(INLAND_SC, (byte) 0x0B));
		add("VIE", new TokenEntry(INLAND_SC, (byte) 0x0C));
		add("WAR", new TokenEntry(INLAND_SC, (byte) 0x0D));
		// Sea non-SC provinces (0x52)
		add("ADR", new TokenEntry(SEA_NON_SC, (byte) 0x0E));
		add("AEG", new TokenEntry(SEA_NON_SC, (byte) 0x0F));
		add("BAL", new TokenEntry(SEA_NON_SC, (byte) 0x10));
		add("BAR", new TokenEntry(SEA_NON_SC, (byte) 0x11));
		add("BLA", new TokenEntry(SEA_NON_SC, (byte) 0x12));
		add("EAS", new TokenEntry(SEA_NON_SC, (byte) 0x13));
		add("ECH", new TokenEntry(SEA_NON_SC, (byte) 0x14));
		add("GOB", new TokenEntry(SEA_NON_SC, (byte) 0x15));
		add("GOL", new TokenEntry(SEA_NON_SC, (byte) 0x16));
		add("HEL", new TokenEntry(SEA_NON_SC, (byte) 0x17));
		add("ION", new TokenEntry(SEA_NON_SC, (byte) 0x18));
		add("IRI", new TokenEntry(SEA_NON_SC, (byte) 0x19));
		add("MAO", new TokenEntry(SEA_NON_SC, (byte) 0x1A));
		add("NAO", new TokenEntry(SEA_NON_SC, (byte) 0x1B));
		add("NTH", new TokenEntry(SEA_NON_SC, (byte) 0x1C));
		add("NWG", new TokenEntry(SEA_NON_SC, (byte) 0x1D));
		add("SKA", new TokenEntry(SEA_NON_SC, (byte) 0x1E));
		add("TYS", new TokenEntry(SEA_NON_SC, (byte) 0x1F));
		add("WES", new TokenEntry(SEA_NON_SC, (byte) 0x20));
		// Coastal non-SC provinces (0x54)
		add("ALB", new TokenEntry(COASTAL_NON_SC, (byte) 0x21));
		add("APU", new TokenEntry(COASTAL_NON_SC, (byte) 0x22));
		add("ARM", new TokenEntry(COASTAL_NON_SC, (byte) 0x23));
		add("CLY", new TokenEntry(COASTAL_NON_SC, (byte) 0x24));
		add("FIN", new TokenEntry(COASTAL_NON_SC, (byte) 0x25));
		add("GAS", new TokenEntry(COASTAL_NON_SC, (byte) 0x26));
		add("LVN", new TokenEntry(COASTAL_NON_SC, (byte) 0x27));
		add("NAF", new TokenEntry(COASTAL_NON_SC, (byte) 0x28));
		add("PIC", new TokenEntry(COASTAL_NON_SC, (byte) 0x29));
		add("PIE", new TokenEntry(COASTAL_NON_SC, (byte) 0x2A));
		add("PRU", new TokenEntry(COASTAL_NON_SC, (byte) 0x2B));
		add("SYR", new TokenEntry(COASTAL_NON_SC, (byte) 0x2C));
		add("TUS", new TokenEntry(COASTAL_NON_SC, (byte) 0x2D));
		add("WAL", new TokenEntry(COASTAL_NON_SC, (byte) 0x2E));
		add("YOR", new TokenEntry(COASTAL_NON_SC, (byte) 0x2F));
		// Coastal SC provinces (0x55)
		add("ANK", new TokenEntry(COASTAL_SC, (byte) 0x30));
		add("BEL", new TokenEntry(COASTAL_SC, (byte) 0x31));
		add("BER", new TokenEntry(COASTAL_SC, (byte) 0x32));
		add("BRE", new TokenEntry(COASTAL_SC, (byte) 0x33));
		add("CON", new TokenEntry(COASTAL_SC, (byte) 0x34));
		add("DEN", new TokenEntry(COASTAL_SC, (byte) 0x35));
		add("EDI", new TokenEntry(COASTAL_SC, (byte) 0x36));
		add("GRE", new TokenEntry(COASTAL_SC, (byte) 0x37));
		add("HOL", new TokenEntry(COASTAL_SC, (byte) 0x38));
		add("KIE", new TokenEntry(COASTAL_SC, (byte) 0x39));
		add("LON", new TokenEntry(COASTAL_SC, (byte) 0x3A));
		add("LVP", new TokenEntry(COASTAL_SC, (byte) 0x3B));
		add("MAR", new TokenEntry(COASTAL_SC, (byte) 0x3C));
		add("NAP", new TokenEntry(COASTAL_SC, (byte) 0x3D));
		add("NWY", new TokenEntry(COASTAL_SC, (byte) 0x3E));
		add("POR", new TokenEntry(COASTAL_SC, (byte) 0x3F));
		add("ROM", new TokenEntry(COASTAL_SC, (byte) 0x40));
		add("RUM", new TokenEntry(COASTAL_SC, (byte) 0x41));
		add("SEV", new TokenEntry(COASTAL_SC, (byte) 0x42));
		add("SMY", new TokenEntry(COASTAL_SC, (byte) 0x43));
		add("SWE", new TokenEntry(COASTAL_SC, (byte) 0x44));
		add("TRI", new TokenEntry(COASTAL_SC, (byte) 0x45));
		add("TUN", new TokenEntry(COASTAL_SC, (byte) 0x46));
		add("VEN", new TokenEntry(COASTAL_SC, (byte) 0x47));
		// Bi-coastal SC provinces (0x57)
		add("BUL", new TokenEntry(BI_COASTAL_SC, (byte) 0x48));
		add("SPA", new TokenEntry(BI_COASTAL_SC, (byte) 0x49));
		add("STP", new TokenEntry(BI_COASTAL_SC, (byte) 0x4A));
		isStandard = true;
	}

	/**
	 * Convert a token from its bit pattern to its mnemonic representation.
	 * 
	 * @param tok
	 *        the bit pattern as a <code>StandardToken</code>.
	 * @return the mnemonic representation of the bit pattern.
	 * @throws InvalidTokenException
	 *         if the bits supplied does not correspond to a known token. This
	 *         will also be thrown if conversion of a text token is attempted.
	 */
	public String convert(StandardToken tok) throws InvalidTokenException {
		String token = bitsMap.get(tok);
		if (token == null) {

			throw new InvalidTokenException(new InvalidToken("UNKNOWN"));
		}

		return token;

	}

	/**
	 * Convert a token from mnemonic representation to its bit pattern. Text
	 * tokens are not to be converted this way. The method
	 * <code>convertText</code> can be used to convert a textual string to a
	 * byte array.
	 * 
	 * @param token
	 *        the mnemonic representation.
	 * @return the bit pattern in a byte[2].
	 * @throws InvalidTokenException
	 *         if the token supplied does not correspond to a known token.
	 * @see #convertText
	 */
	public StandardToken convert(String token) throws InvalidTokenException {
		CommonToken tok = tokenMap.get(token);
		if (tok == null) {
			throw new InvalidTokenException(new InvalidToken(token));
		}
		else {
			return new StandardToken(tok.getType(), tok.getSubType(), this);
		}
	}

	/**
	 * Converts a textual string, surrounded by <code>'</code>, to its byte
	 * representation.
	 * 
	 * @param text
	 *        The text to convert.
	 * @return the bit representation for the text.
	 */
	public byte[] convertText(String text) {
		try {
			byte[] bytes = text.getBytes("US-ASCII");
			if (bytes.length < 2 || bytes[0] != '\'' || bytes[bytes.length - 1] != '\'') {
				throw new IllegalArgumentException("String not surrounded " + "by single quotes");
			}

			byte[] res = new byte[(bytes.length - 2) * 2];
			for (int i = 0; i < res.length; i += 2) {
				res[i] = 0x4B;
				res[i + 1] = bytes[i / 2 + 1];
			}
			return res;
		}
		catch (UnsupportedEncodingException uee) {
			uee.printStackTrace();
			System.exit(1);
			return null;
		}
	}

	/**
	 * Gets whether or not this is a valid token.
	 * 
	 * @param token
	 *        The token we are checking the validity of.
	 * @return True if the token is valid, false otherwise.
	 */
	public boolean isValidToken(StandardToken token) {
		return bitsMap.containsKey(token);
	}

	/**
	 * Gets the RM message for this mapping
	 * 
	 * @return A byte array representing the RM.
	 */
	public byte[] getRM() {
		if (isStandard) {
			return new byte[] { 0x1, 0x0, 0x0, 0x0 };
		}
		int len = rmTokens.size() * 6;
		byte[] rm = new byte[len + 4];

		rm[0] = 1;
		rm[2] = (byte) (len >> 8 & 0xFF);
		rm[3] = (byte) (len & 0xFF);

		int curIndex = 4;
		byte[] strBytes;

		for (CommonToken tok : rmTokens) {
			rm[curIndex] = tok.getType();
			rm[curIndex + 1] = tok.getSubType();
			strBytes = bitsMap.get(tok).getBytes();
			rm[curIndex + 2] = strBytes[0];
			rm[curIndex + 3] = strBytes[1];
			rm[curIndex + 4] = strBytes[2];
			curIndex += 6;

		}
		return rm;
	}

	/**
	 * Adds a token to the mapping, but does not add it to the representation
	 * message.
	 * 
	 * @param mnemonic
	 *        The mnemonic representation
	 * @param token
	 *        The token representation
	 */
	private void add_private(String mnemonic, CommonToken token) {
		bitsMap.put(token, mnemonic);
		tokenMap.put(mnemonic, token);
	}

	/**
	 * Create the mapping between tokens and bit patterns.
	 */
	private void createTokenMap() {
		// Misc (0x40)
		add_private("(", new TokenEntry(MISC, Miscellaneous.BRA));
		add_private(")", new TokenEntry(MISC, Miscellaneous.KET));
		// Unit types (0x42)
		add_private("AMY", new TokenEntry(UNIT_TYPES, UnitTypes.AMY));
		add_private("FLT", new TokenEntry(UNIT_TYPES, UnitTypes.FLT));
		// Orders (0x43)
		add_private("CTO", new TokenEntry(ORDERS, Orders.CTO));
		add_private("CVY", new TokenEntry(ORDERS, Orders.CVY));
		add_private("HLD", new TokenEntry(ORDERS, Orders.HLD));
		add_private("MTO", new TokenEntry(ORDERS, Orders.MTO));
		add_private("SUP", new TokenEntry(ORDERS, Orders.SUP));
		add_private("VIA", new TokenEntry(ORDERS, Orders.VIA));
		add_private("DSB", new TokenEntry(ORDERS, Orders.DSB));
		add_private("RTO", new TokenEntry(ORDERS, Orders.RTO));
		add_private("BLD", new TokenEntry(ORDERS, Orders.BLD));
		add_private("REM", new TokenEntry(ORDERS, Orders.REM));
		add_private("WVE", new TokenEntry(ORDERS, Orders.WVE));
		// Order notes (0x44)
		add_private("MBV", new TokenEntry(ORDER_NOTES, OrderNotes.MBV));
		add_private("BPR", new TokenEntry(ORDER_NOTES, OrderNotes.BPR));
		add_private("CST", new TokenEntry(ORDER_NOTES, OrderNotes.CST));
		add_private("ESC", new TokenEntry(ORDER_NOTES, OrderNotes.ESC));
		add_private("FAR", new TokenEntry(ORDER_NOTES, OrderNotes.FAR));
		add_private("HSC", new TokenEntry(ORDER_NOTES, OrderNotes.HSC));
		add_private("NAS", new TokenEntry(ORDER_NOTES, OrderNotes.NAS));
		add_private("NMB", new TokenEntry(ORDER_NOTES, OrderNotes.NMB));
		add_private("NMR", new TokenEntry(ORDER_NOTES, OrderNotes.NMR));
		add_private("NRN", new TokenEntry(ORDER_NOTES, OrderNotes.NRN));
		add_private("NRS", new TokenEntry(ORDER_NOTES, OrderNotes.NRS));
		add_private("NSA", new TokenEntry(ORDER_NOTES, OrderNotes.NSA));
		add_private("NSC", new TokenEntry(ORDER_NOTES, OrderNotes.NSC));
		add_private("NSF", new TokenEntry(ORDER_NOTES, OrderNotes.NSF));
		add_private("NSP", new TokenEntry(ORDER_NOTES, OrderNotes.NSP));
		add_private("NST", new TokenEntry(ORDER_NOTES, OrderNotes.NST));
		add_private("NSU", new TokenEntry(ORDER_NOTES, OrderNotes.NSU));
		add_private("NVR", new TokenEntry(ORDER_NOTES, OrderNotes.NVR));
		add_private("NYU", new TokenEntry(ORDER_NOTES, OrderNotes.NYU));
		add_private("YSC", new TokenEntry(ORDER_NOTES, OrderNotes.YSC));
		// Results (0x45)
		add_private("SUC", new TokenEntry(RESULTS, Results.SUC));
		add_private("BNC", new TokenEntry(RESULTS, Results.BNC));
		add_private("CUT", new TokenEntry(RESULTS, Results.CUT));
		add_private("DSR", new TokenEntry(RESULTS, Results.DSR));
		add_private("FLD", new TokenEntry(RESULTS, Results.FLD));
		add_private("NSO", new TokenEntry(RESULTS, Results.NSO));
		add_private("RET", new TokenEntry(RESULTS, Results.RET));
		// Coasts (0x46)
		add_private("NCS", new TokenEntry(COASTS, Coasts.NCS));
		add_private("NEC", new TokenEntry(COASTS, Coasts.NEC));
		add_private("ECS", new TokenEntry(COASTS, Coasts.ECS));
		add_private("SEC", new TokenEntry(COASTS, Coasts.SEC));
		add_private("SCS", new TokenEntry(COASTS, Coasts.SCS));
		add_private("SWC", new TokenEntry(COASTS, Coasts.SWC));
		add_private("WCS", new TokenEntry(COASTS, Coasts.WCS));
		add_private("NWC", new TokenEntry(COASTS, Coasts.NWC));
		// Phases (0x47)
		add_private("SPR", new TokenEntry(PHASES, Phases.SPR));
		add_private("SUM", new TokenEntry(PHASES, Phases.SUM));
		add_private("FAL", new TokenEntry(PHASES, Phases.FAL));
		add_private("AUT", new TokenEntry(PHASES, Phases.AUT));
		add_private("WIN", new TokenEntry(PHASES, Phases.WIN));
		// Commands (0x48)
		add_private("CCD", new TokenEntry(COMMANDS, Commands.CCD));
		add_private("DRW", new TokenEntry(COMMANDS, Commands.DRW)); // Implemented
		add_private("FRM", new TokenEntry(COMMANDS, Commands.FRM));
		add_private("GOF", new TokenEntry(COMMANDS, Commands.GOF)); // Implemented
		add_private("HLO", new TokenEntry(COMMANDS, Commands.HLO)); // Implemented
		add_private("HST", new TokenEntry(COMMANDS, Commands.HST)); // Implemented
		add_private("HUH", new TokenEntry(COMMANDS, Commands.HUH)); // Implemented
		add_private("IAM", new TokenEntry(COMMANDS, Commands.IAM)); // Implemented
		add_private("LOD", new TokenEntry(COMMANDS, Commands.LOD)); // Implemented
		add_private("MAP", new TokenEntry(COMMANDS, Commands.MAP)); // Implemented
		add_private("MDF", new TokenEntry(COMMANDS, Commands.MDF)); // Implemented
		add_private("MIS", new TokenEntry(COMMANDS, Commands.MIS)); // Implemented
		add_private("NME", new TokenEntry(COMMANDS, Commands.NME)); // Implemented
		add_private("NOT", new TokenEntry(COMMANDS, Commands.NOT)); // Implemented
		add_private("NOW", new TokenEntry(COMMANDS, Commands.NOW)); // Implemented
		add_private("OBS", new TokenEntry(COMMANDS, Commands.OBS)); // Implemented
		add_private("OFF", new TokenEntry(COMMANDS, Commands.OFF)); // Implemented
		add_private("ORD", new TokenEntry(COMMANDS, Commands.ORD)); // Implemented
		add_private("OUT", new TokenEntry(COMMANDS, Commands.OUT));
		add_private("PRN", new TokenEntry(COMMANDS, Commands.PRN)); // Implemented
		add_private("REJ", new TokenEntry(COMMANDS, Commands.REJ)); // Implemented
		add_private("SCO", new TokenEntry(COMMANDS, Commands.SCO)); // Implemented
		add_private("SLO", new TokenEntry(COMMANDS, Commands.SLO)); // Implemented
		add_private("SND", new TokenEntry(COMMANDS, Commands.SND));
		add_private("SUB", new TokenEntry(COMMANDS, Commands.SUB)); // Implemented
		add_private("SVE", new TokenEntry(COMMANDS, Commands.SVE)); // Implemented
		add_private("THX", new TokenEntry(COMMANDS, Commands.THX)); // Implemented
		add_private("TME", new TokenEntry(COMMANDS, Commands.TME)); // Implemented
		add_private("YES", new TokenEntry(COMMANDS, Commands.YES)); // Implemented
		add_private("ADM", new TokenEntry(COMMANDS, Commands.ADM)); // Implemented
		add_private("SMR", new TokenEntry(COMMANDS, Commands.SMR));
		// Total Implemented: 26 of 31
		// Parameters (0x49)
		add_private("AOA", new TokenEntry(PARAMETERS, Parameters.AOA));
		add_private("BTL", new TokenEntry(PARAMETERS, Parameters.BTL));
		add_private("ERR", new TokenEntry(PARAMETERS, Parameters.ERR));
		add_private("LVL", new TokenEntry(PARAMETERS, Parameters.LVL));
		add_private("MRT", new TokenEntry(PARAMETERS, Parameters.MRT));
		add_private("MTL", new TokenEntry(PARAMETERS, Parameters.MTL));
		add_private("NPB", new TokenEntry(PARAMETERS, Parameters.NPB));
		add_private("NPR", new TokenEntry(PARAMETERS, Parameters.NPR));
		add_private("PDA", new TokenEntry(PARAMETERS, Parameters.PDA));
		add_private("PTL", new TokenEntry(PARAMETERS, Parameters.PTL));
		add_private("RTL", new TokenEntry(PARAMETERS, Parameters.RTL));
		add_private("UNO", new TokenEntry(PARAMETERS, Parameters.UNO));
		add_private("DSD", new TokenEntry(PARAMETERS, Parameters.DSD));
		// Press (0x4A)
		add_private("ALY", new TokenEntry(PRESS, Press.ALY));
		add_private("AND", new TokenEntry(PRESS, Press.AND));
		add_private("BWX", new TokenEntry(PRESS, Press.BWX));
		add_private("DMZ", new TokenEntry(PRESS, Press.DMZ));
		add_private("ELS", new TokenEntry(PRESS, Press.ELS));
		add_private("EXP", new TokenEntry(PRESS, Press.EXP));
		add_private("FWD", new TokenEntry(PRESS, Press.FWD));
		add_private("FCT", new TokenEntry(PRESS, Press.FCT));
		add_private("FOR", new TokenEntry(PRESS, Press.FOR));
		add_private("HOW", new TokenEntry(PRESS, Press.HOW));
		add_private("IDK", new TokenEntry(PRESS, Press.IDK));
		add_private("IFF", new TokenEntry(PRESS, Press.IFF));
		add_private("INS", new TokenEntry(PRESS, Press.INS));
		add_private("IOU", new TokenEntry(PRESS, Press.IOU));
		add_private("OCC", new TokenEntry(PRESS, Press.OCC));
		add_private("ORR", new TokenEntry(PRESS, Press.ORR));
		add_private("PCE", new TokenEntry(PRESS, Press.PCE));
		add_private("POB", new TokenEntry(PRESS, Press.POB));
		add_private("PPT", new TokenEntry(PRESS, Press.PPT));
		add_private("PRP", new TokenEntry(PRESS, Press.PRP));
		add_private("QRY", new TokenEntry(PRESS, Press.QRY));
		add_private("SCD", new TokenEntry(PRESS, Press.SCD));
		add_private("SRY", new TokenEntry(PRESS, Press.SRY));
		add_private("SUG", new TokenEntry(PRESS, Press.SUG));
		add_private("THK", new TokenEntry(PRESS, Press.THK));
		add_private("THN", new TokenEntry(PRESS, Press.THN));
		add_private("TRY", new TokenEntry(PRESS, Press.TRY));
		add_private("UOM", new TokenEntry(PRESS, Press.UOM));
		add_private("VSS", new TokenEntry(PRESS, Press.VSS));
		add_private("WHT", new TokenEntry(PRESS, Press.WHT));
		add_private("WHY", new TokenEntry(PRESS, Press.WHY));
		add_private("XDO", new TokenEntry(PRESS, Press.XDO));
		add_private("XOY", new TokenEntry(PRESS, Press.XOY));
		add_private("YDO", new TokenEntry(PRESS, Press.YDO));
		add_private("CHO", new TokenEntry(PRESS, Press.CHO));
		add_private("BCC", new TokenEntry(PRESS, Press.BCC));
		add_private("UNT", new TokenEntry(PRESS, Press.UNT));

		if (tokenMap.size() != bitsMap.size()) {
			System.err.println(TokenMap.class.getName() + ": tokenMap does not contain an 1-1 mapping!");
		}

	}

}
